﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace intTrans
{
    class ModeFilter
    {
        private int ha;
        private Bitmap BitPic, newBmp;
        private int windowsize;
        /*win értékei: r, g, b*/
        private List<int> r = new List<int>();
        private List<int> g = new List<int>();
        private List<int> b = new List<int>();
        private List<int> medianR = new List<int>();
        private List<int> medianG = new List<int>();
        private List<int> medianB = new List<int>();
        private List<int> med = new List<int>();        //3 elemű tömb: R, G, B
        private List<int> ave = new List<int>();        //3 elemű tömb: R, G, B
        private int sumR, sumG, sumB;
        private List<int> upper = new List<int>();      //3 elemű tömb: R, G, B
        private List<int> lower = new List<int>();      //3 elemű tömb: R, G, B
        private List<int> trunR = new List<int>();
        private List<int> trunG = new List<int>();
        private List<int> trunB = new List<int>();
        private List<int> newpic = new List<int>();     //3 elemű tömb: R, G, B

        public ModeFilter(string filename, string wsze)
        {
            string[] ws = wsze.Split('x');
            windowsize = int.Parse(ws[0]);
            BitPic = new Bitmap(filename);
            if (BitPic.PixelFormat == PixelFormat.Format8bppIndexed)
            {
                newBmp = new Bitmap(BitPic.Width, BitPic.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                using (Graphics gfx = Graphics.FromImage(newBmp))
                {
                    gfx.DrawImage(BitPic, 0, 0);
                }
                BitPic = newBmp;
            }
        }

        public Bitmap Transform(ProgressBar progbar)
        {
            ha = windowsize / 2;
            progbar.Maximum = BitPic.Width - ha;
            progbar.Value = 0;
            for (int x = ha; x < BitPic.Width - ha; x++)
            {
                for (int y = ha; y < BitPic.Height - ha; y++)
                {
                    r.Clear();
                    g.Clear();
                    b.Clear();
                    for (int i = 0; i < windowsize * windowsize; i++)
                    {
                        submatrix(x, y, i);
                    }
                    median();
                    mean();
                    set_upper_lower();

                    /*vágás*/
                    trunR.Clear();
                    trunG.Clear();
                    trunB.Clear();
                    for (int j = 0; j < windowsize * windowsize; j++)
                    {
                        if ((r[j] < upper[0] && med[0] < ave[0]) || (r[j] > lower[0] && med[0] > ave[0]))
                        {
                            trunR.Add(r[j]);
                        }
                        if ((g[j] < upper[1] && med[1] < ave[1]) || (g[j] > lower[1] && med[1] > ave[1]))
                        {
                            trunG.Add(g[j]);
                        }
                        if ((b[j] < upper[2] && med[2] < ave[2]) || (b[j] > lower[2] && med[2] > ave[2]))
                        {
                            trunB.Add(b[j]);
                        }
                    }
                    newpic.Clear();
                    if (trunR.Count > 0)
                    {
                        trunR.Sort();
                        newpic.Add(trunR[trunR.Count / 2]);
                    }
                    else
                    {
                        newpic.Add(med[0]);
                    }

                    if (trunG.Count > 0)
                    {
                        trunG.Sort();
                        newpic.Add(trunG[trunG.Count / 2]);
                    }
                    else
                    {
                        newpic.Add(med[1]);
                    }

                    if (trunB.Count > 0)
                    {
                        trunB.Sort();
                        newpic.Add(trunB[trunB.Count / 2]);
                    }
                    else
                    {
                        newpic.Add(med[2]);
                    }
                    BitPic.SetPixel(x, y, Color.FromArgb(newpic[0], newpic[1], newpic[2]));
                }
                progbar.Value++;
            }
            return BitPic;
        }

        /*kernel window feltöltése*/
        public void submatrix(int x, int y, int index)
        {
            r.Add((BitPic.GetPixel(x + (index % windowsize) - ha, y + (index / windowsize) - ha)).R);
            g.Add((BitPic.GetPixel(x + (index % windowsize) - ha, y + (index / windowsize) - ha)).G);
            b.Add((BitPic.GetPixel(x + (index % windowsize) - ha, y + (index / windowsize) - ha)).B);
        }

        /*medián érték megállapítása a kernel window alapján*/
        public void median()
        {
            medianR.Clear();
            medianG.Clear();
            medianB.Clear();
            for (int i = 0; i < windowsize * windowsize; i++)
            {
                medianR.Add(r[i]);
                medianG.Add(g[i]);
                medianB.Add(b[i]);
            }

            medianR.Sort();
            medianG.Sort();
            medianB.Sort();

            med.Clear();
            med.Add(medianR[medianR.Count / 2]);
            med.Add(medianG[medianG.Count / 2]);
            med.Add(medianB[medianB.Count / 2]);
        }

        /*átlag érték megállapítása a kernel window alapján*/
        public void mean()
        {
            sumR = 0;
            sumG = 0;
            sumB = 0;
            for (int i = 0; i < r.Count; i++)
            {
                sumR += r[i];
                sumG += g[i];
                sumB += b[i];
            }
            ave.Clear();
            ave.Add(sumR / r.Count);
            ave.Add(sumG / g.Count);
            ave.Add(sumB / b.Count);
        }

        /*A vágás felső és alső határainak megállapítása*/
        public void set_upper_lower()
        {
            upper.Clear();
            lower.Clear();
            upper.Add(2 * med[0] - medianR[0]);
            upper.Add(2 * med[1] - medianG[0]);
            upper.Add(2 * med[2] - medianB[0]);
            lower.Add(2 * med[0] - medianR[medianR.Count - 1]);
            lower.Add(2 * med[1] - medianG[medianG.Count - 1]);
            lower.Add(2 * med[2] - medianB[medianB.Count - 1]);
        }
    }
}